package org.intellij.markdown.flavours

import org.intellij.markdown.IElementType
import org.intellij.markdown.html.GeneratingProvider
import org.intellij.markdown.html.URI
import org.intellij.markdown.lexer.MarkdownLexer
import org.intellij.markdown.lexer._MarkdownLexer
import org.intellij.markdown.parser.LinkMap
import org.intellij.markdown.parser.MarkerProcessor
import org.intellij.markdown.parser.MarkerProcessorFactory
import org.intellij.markdown.parser.MutableMarkerProcessor
import org.intellij.markdown.parser.markerblocks.MarkerBlock
import org.intellij.markdown.parser.markerblocks.MarkerBlockProvider
import org.intellij.markdown.parser.sequentialparsers.MutableSequentialParserManager
import org.intellij.markdown.parser.sequentialparsers.SequentialParser
import org.intellij.markdown.parser.sequentialparsers.SequentialParserManager
import kotlin.reflect.KClass

typealias GeneratingProviderFactory = (linkMap: LinkMap, baseURI: URI?)->GeneratingProvider

class MutableMarkdownFlavourDescriptor(
    var inlinesLexer :MarkdownLexer = MarkdownLexer(_MarkdownLexer())
) : MarkdownFlavourDescriptor {

    val markerBlockProviders:MutableMap<KClass<out MarkerBlock>,MarkerBlockProvider<MarkerProcessor.StateInfo>> = mutableMapOf()

    val parserSequence :MutableMap<String,SequentialParser>  = mutableMapOf()

    val htmlGeneratingProviders:MutableMap<IElementType,GeneratingProvider> = mutableMapOf()

    val htmlGeneratingProvidersFactory:MutableMap<IElementType,GeneratingProviderFactory> = mutableMapOf()

    val htmlGeneratingProvidersBlock:MutableList<(linkMap: LinkMap, baseURI: URI?)->Map<IElementType, GeneratingProvider>> = mutableListOf()

    override val markerProcessorFactory: MarkerProcessorFactory = MutableMarkerProcessor.Factory(markerBlockProviders.values.toMutableList())

    override val sequentialParserManager: SequentialParserManager = MutableSequentialParserManager(parserSequence.values.toMutableList())

    override fun createHtmlGeneratingProviders(
        linkMap: LinkMap,
        baseURI: URI?,
    ): Map<IElementType, GeneratingProvider>{
        htmlGeneratingProvidersBlock.forEach {
            it(linkMap, baseURI).forEach {
                htmlGeneratingProviders[it.key] = it.value
            }
        }

        return htmlGeneratingProviders + htmlGeneratingProvidersFactory.map { it.key to it.value(linkMap, baseURI) }
    }


    override fun createInlinesLexer(): MarkdownLexer = inlinesLexer

    fun registerHtmlGeneratingProvider(type:IElementType,factory:GeneratingProviderFactory){
        htmlGeneratingProvidersFactory[type] = factory
    }

    fun registerHtmlGeneratingProvider(block:(linkMap: LinkMap, baseURI: URI?)->Map<IElementType, GeneratingProvider>){
        htmlGeneratingProvidersBlock.add(block)
    }

    fun registerSequentialParser(vararg parser: SequentialParser){
        parser.forEach {
            parserSequence[it::class.simpleName!!]=it
        }
    }

    fun registerSequentialParser(key:String,parser:SequentialParser){
        parserSequence[key]=parser
    }

    fun registerMarkerBlockProvider(key:KClass<out MarkerBlock>, markerBlockProvider: MarkerBlockProvider<MarkerProcessor.StateInfo>){
        markerBlockProviders[key]=markerBlockProvider
    }

    fun registerMarkerBlockProvider(vararg markerBlockProvider:Pair<KClass<out MarkerBlock>, MarkerBlockProvider<MarkerProcessor.StateInfo>>){
        markerBlockProvider.forEach {
            markerBlockProviders[it.first] = it.second
        }
    }
}